﻿
Imports std

Public Class unittest
    Public Class fceslite
        Private Shared f As freclust.fceslite(Of _false) = Nothing
        Private Shared m As map(Of Int64, Int64) = Nothing
        Private Shared lock As sequentialLock = Nothing

        Private Shared Function randomkey() As Int64
            If m.size() = 0 OrElse rnd(0, 1) < 0.5 Then
                Return rnd(0, Convert.ToInt32(maxInt16) + 1, True)
            Else
                Dim it As map(Of Int64, Int64).iterator = Nothing
                it = m.begin()
                For i As Int32 = 0 To rnd(0, m.size(), True) - 1
                    it += 1
                Next
                Return (+it).first()
            End If
        End Function

        Private Shared Function randombuff() As bytes
            Dim rtn As bytes = Nothing
            rtn = New bytes()
            rtn.size() = rnd(0, 1024 * 8 + 1, True)
            For i As Int32 = 0 To rnd(0, 1024 + 1, True) - 1
                rtn(rnd(0, rtn.size(), True)) = rndbyte()
            Next
            Return rtn
        End Function

        Private Shared Sub _read(ByVal key As Int64)
            Dim buff As bytes = Nothing
            Dim readsuc As Boolean
            readsuc = f.read(key, buff)
            assert(readsuc = (m.find(key) <> m.end()))
            If readsuc Then
                assert(buff.size() = m(key))
            End If
        End Sub

        Private Shared Sub write()
            lock.wait()
            Dim inputkey As Int64
            inputkey = randomkey()
            Dim buff As bytes = Nothing
            buff = randombuff()
            Dim outputkey As Int64
            Dim size As Int64
            size = buff.size()
            assert(f.write(inputkey, buff, outputkey))
            assert(size = buff.size())
            If inputkey = outputkey Then
                m(inputkey) = buff.size()
            Else
                m.erase(inputkey)
                m(outputkey) = buff.size()
            End If
            _read(inputkey)
            _read(outputkey)
            lock.release()
        End Sub

        Private Shared Sub append()
            lock.wait()
            Dim inputkey As Int64
            inputkey = randomkey()
            Dim buff As bytes = Nothing
            buff = randombuff()
            Dim outputkey As Int64
            Dim size As Int64
            size = buff.size()
            assert(f.append(inputkey, buff, outputkey))
            assert(size = buff.size())
            If inputkey = outputkey Then
                m(inputkey) += buff.size()
            Else
                If m.find(inputkey) <> m.end() Then
                    m(outputkey) = m(inputkey) + buff.size()
                    m.erase(inputkey)
                Else
                    m(outputkey) = buff.size()
                End If
            End If
            _read(inputkey)
            _read(outputkey)
            lock.release()
        End Sub

        Private Shared Sub read()
            lock.wait()
            _read(randomkey())
            lock.release()
        End Sub

        Private Shared Sub delete()
            lock.wait()
            Dim key As Int64
            key = randomkey()
            Dim delsuc As Boolean
            delsuc = f.delete(key)
            assert(delsuc = (m.find(key) <> m.end()))
            If delsuc Then
                m.erase(key)
                _read(key)
            End If
            lock.release()
        End Sub

        Private Shared Sub run()
            Dim round As Int64
            round = 10000
            If isreleasebuild() Then
                round <<= 1
            End If

            randomrun.invoke(round, CType(Nothing, Object), _
                             New randomrun.info(AddressOf write, 0.2), _
                             New randomrun.info(AddressOf append, 0.3), _
                             New randomrun.info(AddressOf read, 0.2), _
                             New randomrun.info(AddressOf delete, 0.2))
        End Sub

        Public Shared Sub go()
            raiseError(errorHandle.errorType.application, "******** start fceslite automatical unittest ********")
            Dim file As String = Nothing
            file = combinepath(filesystem.temppath(), createGUID())
            m = New map(Of Int64, Int64)()
            lock = New sequentialLock()

            For i As Int32 = 0 To 3
                f = New freclust.fceslite(Of _false)(file)
                Dim threadCount As Int64
                threadCount = 2
                If isreleasebuild() Then
                    threadCount <<= 1
                End If
                Dim tp As threadpool = Nothing
                tp = New threadpool(threadCount)
                While threadCount > 0
                    tp.insertJob(AddressOf run, Nothing)
                    threadCount -= 1
                End While

                While Not tp.idle()
                    sleep()
                End While
                tp.stop()
                f.close()
            Next
            raiseError(errorHandle.errorType.application, "******** finish fceslite automatical unittest *******")
        End Sub
    End Class
End Class
